package com.pro.framework.api.util;

import com.pro.framework.api.FrameworkConst;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 树形结构工具类，支持列表构建树形结构与树结构扁平化处理。
 */
public class TreeUtil {

    // 定义 UI 元素相关的键常量
    static final String ELEMENT_VALUE = FrameworkConst.Str.UI.Element.TREE_VALUE;
    static final String ELEMENT_LABEL = FrameworkConst.Str.UI.Element.TREE_LABEL;
    static final String TREE_VALUE1 = FrameworkConst.Str.UI.Element.TREE_VALUE1;
    static final String ELEMENT_CHILDREN = FrameworkConst.Str.UI.Element.TREE_CHILDREN;

    /**
     * 将平铺的列表数据构建成树形结构，返回 List<Map<String, Object>> 形式。
     *
     * @param list           原始数据列表
     * @param getCatId       获取分类 ID 的函数
     * @param getParentCatId 获取父分类 ID 的函数
     * @param getName     获取分类名称的函数
     * @param <T>            列表中元素的类型
     * @return 构建好的树形结构列表（仅包含根节点）
     */
    public static <T> List<Map<String, Object>> buildElementTree(
            List<T> list,
            Function<T, Long> getCatId,
            Function<T, Long> getParentCatId,
            Function<T, String> getName,
            Function<T,String> getGroupCode) {

        // 存储每个节点的 map 数据
        Map<Long, Map<String, Object>> elementMap = new HashMap<>();
        // 存储每个节点的父 ID
        Map<Long, Long> idToParentIdMap = new HashMap<>();

        // 初始化每个节点及其父 ID 映射关系
        for (T element : list) {
            Long id = getCatId.apply(element);
            Long parentId = getParentCatId.apply(element);
            idToParentIdMap.put(id, parentId);

            Map<String, Object> node = new HashMap<>();
            node.put(ELEMENT_VALUE, id.toString());
            node.put(ELEMENT_LABEL, getName.apply(element));
            String groupCode = getGroupCode.apply(element);
            if (groupCode != null && !groupCode.isEmpty()) {
                node.put(TREE_VALUE1, groupCode);
            }
            elementMap.put(id, node);
        }

        // 构建父子节点关系
        for (Map.Entry<Long, Map<String, Object>> entry : elementMap.entrySet()) {
            Long id = entry.getKey();
            Long parentId = idToParentIdMap.get(id);
            if (parentId != null && parentId != 0) {
                Map<String, Object> parentNode = elementMap.get(parentId);
                if (parentNode != null) {
                    List<Map<String, Object>> children =
                            (List<Map<String, Object>>) parentNode.computeIfAbsent(ELEMENT_CHILDREN, k -> new ArrayList<>());
                    children.add(entry.getValue());
                }
            }
        }

        // 过滤出根节点，并清理无子节点的 children 字段
        return elementMap.entrySet().stream()
                .filter(entry -> {
                    Long parentId = idToParentIdMap.get(entry.getKey());
                    return parentId == null || parentId == 0;
                })
                .map(Map.Entry::getValue)
                .peek(node -> {
                    List<?> children = (List<?>) node.get(ELEMENT_CHILDREN);
                    if (children == null || children.isEmpty()) {
                        node.remove(ELEMENT_CHILDREN);
                    }
                })
                .collect(Collectors.toList());
    }

    /**
     * 将树形结构扁平化为一个列表。
     *
     * @param treeList    原始树形结构数据
     * @param getChildren 获取子节点列表的函数
     * @param <T>         树节点类型
     * @return 扁平化后的节点列表
     */
    public static <T> List<T> flattenTree(List<T> treeList, Function<T, List<T>> getChildren) {
        List<T> result = new ArrayList<>();
        for (T node : treeList) {
            traverseNode(node, getChildren, result);
        }
        return result;
    }

    /**
     * 递归遍历树节点并收集到结果列表中。
     *
     * @param node        当前节点
     * @param getChildren 获取子节点函数
     * @param result      收集结果的列表
     * @param <T>         节点类型
     */
    private static <T> void traverseNode(T node, Function<T, List<T>> getChildren, List<T> result) {
        result.add(node);
        List<T> children = getChildren.apply(node);
        if (children != null) {
            for (T child : children) {
                traverseNode(child, getChildren, result);
            }
        }
    }

    public static <T, K> List<T> buildTree(
            List<T> list,
            Function<T, K> getId,
            Function<T, K> getParentId,
            BiConsumer<T, List<T>> setChildren
    ) {
        Map<K, T> idMap = list.stream()
                .collect(Collectors.toMap(getId, Function.identity()));

        // 用于聚合所有子节点
        Map<K, List<T>> childrenMap = new HashMap<>();

        List<T> roots = new ArrayList<>();

        for (T node : list) {
            K parentId = getParentId.apply(node);

            if (parentId == null || !idMap.containsKey(parentId)) {
                roots.add(node);
            } else {
                // 将当前节点添加到其父节点对应的子节点列表中
                childrenMap
                        .computeIfAbsent(parentId, k -> new ArrayList<>())
                        .add(node);
            }
        }

        // 第二次遍历，填充子节点
        for (Map.Entry<K, List<T>> entry : childrenMap.entrySet()) {
            T parent = idMap.get(entry.getKey());
            setChildren.accept(parent, entry.getValue());
        }

        return roots;
    }



//    private static <T> List<T> mergeChild(T parent, T child, BiConsumer<T, List<T>> setChildren) {
//        List<T> newList = new ArrayList<>();
//        newList.add(child);
//        return newList;
//    }


    /**
     * 自顶向下遍历树结构，处理每个父节点及其子节点。
     *
     * @param tree        根节点列表
     * @param getChildren 获取子节点的方法
     * @param consumer    处理函数：接受 (父节点, 子节点列表)
     * @param <T>         节点类型
     */
    public static <T> void consume(List<T> tree,
                                   Function<T, List<T>> getChildren,
                                   BiConsumer<T, List<T>> consumer) {
        if (tree == null || tree.isEmpty()) return;
        consumer.accept(null, tree);
        for (T node : tree) {
            List<T> children = getChildren.apply(node);
//            if (children != null && !children.isEmpty()) {
            consumer.accept(node, children);
            consume(children, getChildren, consumer); // 递归处理子节点
//            }
        }
    }

}
